package com.jy.appmarket.newnetwork;

import java.util.concurrent.BlockingQueue;

import android.annotation.TargetApi;
import android.net.TrafficStats;
import android.os.Build;
import android.os.Process;

public class WorkDispatcher extends Thread {
	private final BlockingQueue<Request<?>> mQueue;
	private final Network mNetwork;
	private final Cache mCache;
	private final ResponseDelivery mDelivery;
	private volatile boolean mQuit = false;

	public WorkDispatcher(BlockingQueue<Request<?>> queue, Network network, Cache cache, ResponseDelivery delivery) {
		mQueue = queue;
		mNetwork = network;
		mCache = cache;
		mDelivery = delivery;
	}

	public void quit() {
		mQuit = true;
		interrupt();
	}

	@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
	private void addTrafficStatsTag(Request<?> request) {
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
			TrafficStats.setThreadStatsTag(request.getTrafficStatsTag());
		}
	}

	@Override
	public void run() {
		Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
		mCache.initialize();
		while (true) {
			Request<?> request;
			try {
				request = mQueue.take();
			} catch (InterruptedException e) {
				if (mQuit) {
					return;
				}
				continue;
			}

			try {
				request.addMarker("work-take-request");
				if (request.isCanceled()) {
					request.finish("work-discard-cancelled");
					continue;
				}

				Response<?> response = null;

				if (request.shouldCache()) {
					response = getFromCache(request);
				}

				if (response != null) {
					request.addMarker("cache-return");
					mDelivery.postResponse(request, response);
					continue;
				}

				response = getFromNetwork(request);

				if (request.shouldCache() && response.cacheEntry != null) {
					mCache.put(request.getCacheKey(), response.cacheEntry);
					request.addMarker("work-cache-written");
				}

				mDelivery.postResponse(request, response);
			} catch (VolleyError e) {
				parseAndDeliverNetworkError(request, e);
				// e.printStackTrace();
			} catch (Exception e) {
				NetworkLog.e(e, "Unhandled exception %s", e.toString());
				mDelivery.postError(request, new VolleyError(e));
				// e.printStackTrace();
			}
		}
	}

	private Response<?> getFromCache(final Request<?> request) {
		final String key = request.getCacheKey();
		Cache.Entry entry = mCache.get(key);

		if (entry == null) {
			request.addMarker("cache-not-found");
			return null;
		}

		if (entry.isExpired()) {
			mCache.remove(key);
			request.addMarker("cache-expired");
			return null;
		}

		request.addMarker("cache-hit");
		NetworkResponse resp = new NetworkResponse(entry.data, entry.responseHeaders);
		return request.parseNetworkResponse(resp);
	}

	private Response<?> getFromNetwork(final Request<?> request) throws VolleyError {
		addTrafficStatsTag(request);
		NetworkResponse networkResponse = mNetwork.performRequest(request);
		request.addMarker("network-http-complete");
		Response<?> response = request.parseNetworkResponse(networkResponse);
		request.addMarker("network-parse-complete");
		return response;
	}

	private void parseAndDeliverNetworkError(Request<?> request, VolleyError error) {
		error = request.parseNetworkError(error);
		mDelivery.postError(request, error);
	}
}
